#include <exception>
#include "XmlSaxParser.hpp"
#include "3D/ObjModel.hpp"
#include "3D/Texture2D.hpp"

XmlSaxParser::XmlSaxParser():
    _builtScene(NULL),
    _builtTerrain(NULL),
    _builtVertex(-1),
    _builtIndex(-1),
    _builtVertices(NULL),
    _builtIndexes(NULL),
    _builtModel(NULL),
    _builtTexture(NULL),
    _nextCalledMethod(NULL)
{
    prepareReading();
}

void                    XmlSaxParser::prepareReading()
{
    _filler["scene"] = &XmlSaxParser::fillScene;
    _filler["name"] = &XmlSaxParser::fillName;
    _filler["terrain"] = &XmlSaxParser::fillTerrain;
    _filler["width"] = &XmlSaxParser::fillWidth;
    _filler["height"] = &XmlSaxParser::fillHeight;
    _filler["nb_vertices"] = &XmlSaxParser::fillNbVertices;
    _filler["nb_indexes"] = &XmlSaxParser::fillNbIndexes;
    _filler["vertex"] = &XmlSaxParser::fillVertex;
    _filler["pos_x"] = &XmlSaxParser::fillPosX;
    _filler["pos_y"] = &XmlSaxParser::fillPosY;
    _filler["pos_z"] = &XmlSaxParser::fillPosZ;
    _filler["col_r"] = &XmlSaxParser::fillColR;
    _filler["col_g"] = &XmlSaxParser::fillColG;
    _filler["col_b"] = &XmlSaxParser::fillColB;
    _filler["norm_x"] = &XmlSaxParser::fillNormX;
    _filler["norm_y"] = &XmlSaxParser::fillNormY;
    _filler["norm_z"] = &XmlSaxParser::fillNormZ;
    _filler["text_x"] = &XmlSaxParser::fillTextX;
    _filler["text_y"] = &XmlSaxParser::fillTextY;
    _filler["text_z"] = &XmlSaxParser::fillTextZ;
    _filler["id_x"] = &XmlSaxParser::fillIdX;
    _filler["id_y"] = &XmlSaxParser::fillIdY;
    _filler["id_z"] = &XmlSaxParser::fillIdZ;
    _filler["index"] = &XmlSaxParser::fillIndex;
    _filler["model"] = &XmlSaxParser::fillModel;
    _filler["model_path"] = &XmlSaxParser::fillModelPath;
    _filler["model_pos_x"] = &XmlSaxParser::fillModelPosX;
    _filler["model_pos_y"] = &XmlSaxParser::fillModelPosY;
    _filler["model_pos_z"] = &XmlSaxParser::fillModelPosZ;
    _filler["texture"] = &XmlSaxParser::fillTexture;
    _filler["text_name"] = &XmlSaxParser::fillTextName;
    _filler["text_path"] = &XmlSaxParser::fillTextPath;
    _filler["text_behaviour"] = &XmlSaxParser::fillTextBehaviour;
}

Scene*                  XmlSaxParser::readFile(QString const& fileName)
{
    QFile               file(fileName.toStdString().data());
    QXmlInputSource     source(&file);
    QXmlSimpleReader	reader;

    reader.setContentHandler(this);
    reader.parse(&source);

    if (_builtTerrain != NULL)
    {
        _builtTerrain->setDrawable(_builtTerrainDrawable);
        _builtTerrain->setTexture(_builtTexture);
    }
    _builtScene->setTerrain(_builtTerrain);

    return _builtScene;
}

bool    XmlSaxParser::startElement(const QString &, const QString &, const QString &qName, const QXmlAttributes &)
{
    std::map<std::string, LoaderMember>::iterator	found = _filler.find(qName.toStdString());

    if (found != _filler.end())
    {
        _nextCalledMethod = (*found).second;
    }
    return true;
}

bool    XmlSaxParser::endElement(const QString &, const QString &, const QString &)
{
    return true;
}

bool    XmlSaxParser::characters(const QString &str)
{
    if (_nextCalledMethod != NULL)
    {
        (this->*_nextCalledMethod)(str);
    }
    return true;
}

bool    XmlSaxParser::fatalError(const QXmlParseException &exception)
{
    std::cout << "Error:" << exception.message().toStdString() << std::endl;
    return false;
}

void    XmlSaxParser::fillScene(QString const&)
{
    _builtScene = new Scene();
    _nextCalledMethod = NULL;
}

void    XmlSaxParser::fillName(QString const& data)
{
    _builtScene->setName(data.toStdString());
    _builtScene->setPath(data.toStdString());
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillTerrain(QString const&)
{
    _builtTerrain = new Terrain();
    _builtTerrainDrawable = new DrawableObject();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillWidth(QString const& data)
{
    _builtTerrain->setWidth(data.toInt());
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillHeight(QString const& data)
{
    _builtTerrain->setHeight(data.toInt());
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillNbVertices(QString const& data)
{
    int result = data.toInt();

    _builtVertices = new VertexAttributes[result + 1];
    _builtTerrainDrawable->setVertices(result, _builtVertices);
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillNbIndexes(QString const& data)
{
    int result = data.toInt();

    _builtIndexes = new unsigned int[result + 1];
    _builtTerrainDrawable->setIndex(result, _builtIndexes);
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillVertex(QString const&)
{
    _builtVertex++;
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillPosX(QString const& data)
{
    _builtVertices[_builtVertex].posX = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillPosY(QString const& data)
{
    _builtVertices[_builtVertex].posY = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillPosZ(QString const& data)
{
    _builtVertices[_builtVertex].posZ = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillColR(QString const& data)
{
    _builtVertices[_builtVertex].colorR = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillColG(QString const& data)
{
    _builtVertices[_builtVertex].colorG = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillColB(QString const& data)
{
    _builtVertices[_builtVertex].colorB = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillNormX(QString const& data)
{
    _builtVertices[_builtVertex].normX = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillNormY(QString const& data)
{
    _builtVertices[_builtVertex].normY = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillNormZ(QString const& data)
{
    _builtVertices[_builtVertex].normZ = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillTextX(QString const& data)
{
    _builtVertices[_builtVertex].textX = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillTextY(QString const& data)
{
    _builtVertices[_builtVertex].textY = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillTextZ(QString const& data)
{
    _builtVertices[_builtVertex].textZ = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillIdX(QString const& data)
{
    _builtVertices[_builtVertex].idX = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillIdY(QString const& data)
{
    _builtVertices[_builtVertex].idY = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillIdZ(QString const& data)
{
    _builtVertices[_builtVertex].idZ = data.toFloat();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillIndex(QString const& data)
{
    _builtIndex++;
    _builtIndexes[_builtIndex] = data.toInt();
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillModel(QString const&)
{
    _builtModel = new ObjModel();
    _builtScene->addObject(_builtModel);
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillModelPath(QString const& data)
{
    _builtModel->setPath(data.toStdString());

    try
    {
        _builtModel->load(data.toStdString());
    }
    catch (std::exception e)
    {
        std::cout << e.what() << std::endl;
    }
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillModelPosX(QString const& data)
{
    _builtModel->setPositionX(data.toInt());
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillModelPosY(QString const& data)
{
    _builtModel->setPositionY(data.toInt());
    _nextCalledMethod = NULL;
}

void	XmlSaxParser::fillModelPosZ(QString const& data)
{
    _builtModel->setPositionZ(data.toInt());
    _nextCalledMethod = NULL;
}

void    XmlSaxParser::fillTexture(QString const&)
{
    _builtTexture = new Texture2D();
    _nextCalledMethod = NULL;
}

void    XmlSaxParser::fillTextName(QString const& data)
{
    _builtTexture->setName(data.toStdString());
    _nextCalledMethod = NULL;
}

void    XmlSaxParser::fillTextPath(QString const& data)
{
    _builtTexture->setPath(data.toStdString());
    _builtTexture->load();
    _nextCalledMethod = NULL;
}

void    XmlSaxParser::fillTextBehaviour(QString const& data)
{
    _builtTexture->setBehaviour(static_cast<TextureBehaviour>(data.toInt()));
    _nextCalledMethod = NULL;
}
